package com.abel.bigwater.data.sanchuan

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.data.InvalidPacketException
import com.abel.bigwater.data.JsonDateTimeSerializer
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import io.netty.buffer.ByteBuf
import org.joda.time.DateTime
import kotlin.experimental.and

class FetchDataReplyMonthBill(_dataLen: Int?) : SanchuanData(_dataLen) {
    var cmdid: Short? = FetchCmdType.MonthBill.code

    var cmd: FetchCmdType? = FetchCmdType.MonthBill

    var startDateStr: BcdString? = null

    @JsonSerialize(using = JsonDateTimeSerializer::class)
    var startDate: DateTime? = null
        get() = DateTime(startDateStr!!.bcdArray!![0].toInt() * 100 +
                startDateStr!!.bcdArray!![1].toInt(),
                startDateStr!!.bcdArray!![2].toInt(),
                1, 0, 0)
        set(value) {
            field = value
            startDateStr = if (field == null) null else
                BcdString(byteArrayOf(field!!.year.div(100).toByte(),
                        field!!.year.rem(100).toByte(),
                        field!!.monthOfYear.toByte()), true)
        }

    var decimalBit: Byte? = null

    var dataLongList: List<Long>? = null

    var dataList: List<Double>? = null
        get() {
            val list = ArrayList<Double>(dataLongList!!.size)
            val ratio = Math.pow(10.0, -decimalBit!!.toDouble())
            dataLongList?.forEachIndexed { idx, v1 -> list.add(v1.toDouble() * ratio) }
            field = list
            return field
        }
        set(value) {
            field = value
            if (value == null) {
                dataLongList = null
                return
            }

            val ratio = Math.pow(10.0, decimalBit!!.toDouble()).toInt()
            val list = ArrayList<Long>(value.size)
            field!!.forEachIndexed { idx, d ->
                list.add(d.times(ratio).toLong())
            }

            dataLongList = list
        }


    /**
     * 计算数据长度，针对解析和打包
     */
    override fun computeDataLen(): Int {
        if (dataLen == null) dataLen = 1 + 3 + 1 + 4 * dataLongList!!.size
        return dataLen!!
    }

    /**
     * 从当前位置写入打包字节流
     */
    override fun fillBuffer(buf: ByteBuf) {
        computeDataLen()

        buf.alloc().buffer().apply {
            writeByte(cmdid!!.toInt())

            assert(3 == startDateStr!!.size)
            writeBytes(startDateStr!!.hexArray)

            writeByte(decimalBit!!.toInt())

            dataLongList!!.forEach {
                writeInt(it.toInt())
            }

            // transfer
            buf.writeBytes(this)
        }
    }

    /**
     * 解析字节流，从buf当前位置开始，并且消费其中的字节。
     */
    override fun <T : SanchuanData> parseBuffer(buf: ByteBuf): T? {
        if (dataLen!! < 1 + 3 + 1 + 4) throw  InvalidPacketException("月结数据包不完整: ${dataLen}")

        buf.readBytes(dataLen!!).apply {
            cmdid = readByte().toShort().and(0xFF)
            if (cmdid != FetchCmdType.MonthBill.code) throw IllegalArgumentException("不匹配的命令类型:${cmdid}")

            startDateStr = BcdString.create(this, 3)
            startDate

            decimalBit = readByte()

            val cap = (dataLen!! - 4) / 4
            val list = ArrayList<Long>(cap)
            for (idx in 0..(cap - 1)) {
                list.add(readInt().toLong().and(0xFFFFFFFF))
            }

            dataLongList = list
        }

        return this as T?
    }
}